<?php
/**
 * @author spenceryg
 * @date 2022/12/14
 * @time 3:10 下午
 * @focus love & life
 */


namespace app\auto\lib;


use app\auto\business\FieldBusiness;
use app\auto\business\RelationBusiness;
use app\auto\business\TableBusiness;
use app\auto\model\App;
use app\auto\model\Controller;
use app\auto\model\Field;
use app\auto\model\Method;
use app\auto\model\MethodFiled;
use app\auto\model\Table;
use app\common\lib\Dir;
use Laminas\Code\Generator\DocBlockGenerator;
use Laminas\Code\Generator\ValueGenerator;
use think\helper\Str;

use Laminas\Code\Reflection;

class MethodGenerator
{
    public static function generate($method)
    {
        ViewGenerator::generate($method);
    }


    /**
     * 函数体生成
     * bodyGenerate
     */
    public static function bodyGenerate($method): string
    {
        $controller_id = $method['controller_id'];
        $controller = \app\auto\model\Controller::find($controller_id);
        $controller_classname = Str::studly($controller['name']);
        $app = App::find($controller['app_id']);
        $table_name_no_prefix = Str::snake($controller->name);
        $alias_prefix = $table_name_no_prefix . '__';
        $table_name = env('DATABASE.PREFIX') . $table_name_no_prefix;
        $type = $method['type'];
        $request = $method['request'];
        $code = '';
        if ($request == 'get_view' && $type == 'list') {
            $code .= "if (request()->isPost()) {";
            $code .= "    return error('请求方式错误');";
            $code .= "}";
            $code .= self::getData($method);
            $code .= "View::assign(\$data);";
            $code .= self::getOptions($method);
            $code .= "return View::fetch();";
        }

        if($request == 'post_view' && $type == 'update') {
            $code .= "if (request()->isPost()) {";
            $code .= "  \$data = input();";
            $code .= "  \$data = group_by_table_name(\$data);";
            $code .= "  \app\common\model\\$controller_classname::update(\$data['$table_name_no_prefix']);";

            $code .= "  return success();";
            $code .= "} else{ ";
            $code .= "  \$data = \app\common\model\\$controller_classname::find(input('{$alias_prefix}id'));";
            $code .= "\$r = [];";
            $code .= "foreach(\$data->getData() as \$key => \$val){\$r['{$alias_prefix}'. \$key] = \$val;}";
            $code .= "  View::assign('r',\$r);";
            $code .= self::getOptions($method);
            $code .= "  return View::fetch();";
            $code .= "}";
        }


        if($request == 'post_view' && $type == 'add') {
            $code .= "if (request()->isPost()) {";
            $code .= "  \$data = input();";
            $code .= "  \$data = group_by_table_name(\$data);";
            $code .= "  \app\common\model\\$controller_classname::create(\$data['$table_name_no_prefix']);";
            $code .= "  return success();}";
            $code .= " else{";
            $code .= self::getOptions($method);
            $code .= "  return View::fetch();";
            $code .= "}";
        }

        if($request == 'get' && $type == 'delete') {
            $code .= "\app\common\model\\$controller_classname::destroy(input('{$alias_prefix}id'));";
            $code .= "return success();";
        }




        return $code;


    }


    /**
     * getOptions
     * @param $method
     * @return string
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getOptions($method): string
    {
        $code = '';
        $methodFields = MethodFiled::where('method_id', $method['id'])->select();
        foreach ($methodFields as $method_field) {
            $field = Field::find($method_field['field_id']);
            $table_name = env('DATABASE.PREFIX'). str_replace('_id','' ,$field['name']);
            $relation_table = Table::getByName($table_name);
            $alias = FieldBusiness::getFiledAliasById($field['id']);
            if($field['is_relation']) {
                $mode_class_name = TableBusiness::tableToClass($relation_table['name']);
                $code .= "\${$alias}_option = \\app\\common\\model\\{$mode_class_name}::column('name as name, id as id');";
                $code .= "\$options['{$alias}_options'] = \${$alias}_option;";
            }else{
                if( in_array($field['config']['type'] ,['select', 'radio'])){
                    if($field['confg']['is_sql']) {
                        $code .= "\${$alias}_option = Db::query('{$field['config']['data_set']}');";
                        $code .= "\$options['{$alias}_options'] = \${$alias}_option;";
                    }else{
                        $option_arr = ViewGenerator::getDataSetOptions(ViewGenerator::getRealConfigData($method_field));
                        $option_str = (new ValueGenerator($option_arr))->generate();
                        $code .= "\${$alias}_option = {$option_str};";
                        $code .= "\$options['{$alias}_options'] = \${$alias}_option;";
                    }
                }
                
                if($field['name'] == 'id' && $field->iTable->id != $self_table_id){
                    $controller = \app\auto\model\Controller::find($method['controller_id']);
                    $self_table_name = env('DATABASE.PREFIX') . Str::snake($controller['name']);
                    $self_table_id = Table::where('name', $self_table_name)->value('id');
                    $mode_class_name = TableBusiness::tableToClass($field->iTable->name);
                    $code .= "\${$alias}_option = \\app\\common\\model\\{$mode_class_name}::column('name as name, id as id');";
                    $code .= "\$options['{$alias}_options'] = \${$alias}_option;";
                }
            }
        }
        if($code) {
            $code = '$options = [];' . $code;
            $code .= "View::assign(\$options);";
        }
        return $code;
    }






    /**
     * getData
     * @param $method
     * @return string
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function getData($method): string
    {
        $data = [];
        $id = $method['id'];
        $ins = MethodFiled::where('trend','in')->where('method_id', $id)->select();
        foreach ($ins as $in) {
            $in_field = \app\auto\model\Field::find($in['field_id']);
            $in_table = \app\auto\model\Table::find($in_field['table_id']);
            $data['in_tables'][] = $in_table['name'];
            $data['in_fields'][] = $in_field['name'];
            $data['in_conditions'][] = $in['condition'];
        }

        $outs = MethodFiled::where('trend','out')->where('method_id', $id)->select();
        foreach ($outs as $out) {
            $out_field = \app\auto\model\Field::find($out['field_id']);
            $out_table = \app\auto\model\Table::find($out_field['table_id']);
            $out['table_name'] = $out_table['name'];
            $out['field_name'] = $out_field['name'];
            $out['alias'] = str_replace(env('DATABASE.PREFIX'), '', $out_table['name']) . '__' . $out_field['name'];
            $data['out_tables'][] = $out['table_name'];
            $data['out_fields'][] = $out['field_name'];
            $data['out_alias'][] = $out['alias'];
        }

        $controller_id = $method['controller_id'];
        $controller = \app\auto\model\Controller::find($controller_id);
        $table_name = Str::snake($controller->name);
        $table_name = env('DATABASE.PREFIX') . $table_name;
        $data['table_name'] = $table_name;

        return RelationBusiness::getCode($data) . self::paginateCode($method);
    }


    /**
     * paginateCode
     * @param $method
     * @return string
     */
    public static function paginateCode($method): string
    {
        $listRow = $method['list_row'];
        return <<<EOF
\$data = \$query->paginate(input('listRow')?:{$listRow});
\$data = ['data' => \$data->items(), 'paginate' => \$data->render()];

EOF;
    }




    /**
     * 备注生成
     * commentGenerator
     */
    public static function commentGenerator($method, $longDesc, $tags): DocBlockGenerator
    {
        return new DocBlockGenerator($method['comment'],$longDesc.'-'.$method['name'], $tags);
    }


    /**
     * deleteFromMethod
     * @param $method
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function deleteFromMethod($method)
    {
        $controller = Controller::find($method['controller_id']);
        $app = App::find($controller['app_id']);
        $app_path = "../app/{$app['name']}/";
        $view_path = $app_path . 'view/' . Str::snake($controller['name']) .'/';
        $count = Method::where('controller_id', $controller['id'])->count();
        if($count == 1) {
            Dir::removeDir($view_path);
        } else {
            @unlink($view_path . Str::snake($method['name'] . '.html'));
        }
    }




    public static function getMethodCode($filename, $methodname) {
        $reflection = new FileReflection($filename);

        $method = $reflection->getMethod($methodname);
        if (!$method) {
            return null; // 找不到对应的方法
        }

        return $method->getBodyCode();
    }



}
